#include "Socket.h"

using namespace std;

//Se crea el socket.
Socket::Socket(int port) {
	struct_socket.sin_family = AF_INET;
	struct_socket.sin_port = htons(port);
	struct_socket.sin_addr.s_addr = htonl(INADDR_ANY);
	this->conex_id = 0;
	//se crea el socket y guardo su id en la variable socket_id
	if ((socketId = socket(AF_INET, SOCK_STREAM, 0)) == -1)
		cout << "Error al crear el socket" << endl;

/* Quitado por Abraman Alan Panuccio 26/06/2014 para tomar el puerto cuando corre.
	//esta opcion sirve para poder reusar el puerto y no tener que esperar luego de finalizado el programa
	if (setsockopt(socketId, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(int)) == -1)
		cout << "Error: setsockopt - SO_REUSEADDR" << endl;
	conex_id = socketId;
*/

}

//se llena la estructura para la creación del socket para el cliente
Socket::Socket(int port, string ip) {
	struct_socket.sin_family = AF_INET;
	struct_socket.sin_port = htons(port);
	this->setStruct_Socket(ip); //Este metodo permite recibir ip o nombre.
	//se crea el socket y guardo su id en la variable socket_id
	if ((socketId = socket(AF_INET, SOCK_STREAM, 0)) == -1)
		cout << "Error al crear el socket" << endl;
	conex_id = socketId;
}
// Realizo el Bind y Listen del servidor.
int Socket::bindSocket() {
	int retorno = 0;

	//se crea el bind del socket
	retorno = bind(socketId, (struct sockaddr *) &(struct_socket),sizeof(struct sockaddr));

	//SE valida como salio.
	if (retorno== -1)
		cout << "[ERROR] - Error al crear el bind del socket." << endl; //lanza un mensaje si fallo el bind.

	return retorno;

}
// Realizo el Bind y Listen del servidor.
int Socket::listenSocket() {
	int retorno = 0;

	//se pone el socket en modo escucha
	retorno = listen(socketId, 50);

	//Se valida que halla salido bien.
	if ( retorno == -1)
		cout << "[ERROR] - No se puede inicializar la escucha del socket." << endl;

	return retorno;
}

//Realizo el accept del servidor.
int Socket::acceptClient() {
	unsigned int sin_size = sizeof(struct sockaddr_in);
	if ((conex_id = accept(socketId, (struct sockaddr *) &destino, &sin_size))
			== -1)
		if (errno != EWOULDBLOCK)
			cout << "Error al aceptar el socket" << endl;

	return conex_id;
}
//Conecto el cliente con el servidor
int Socket::connectToServer() {
	if (connect(socketId, (struct sockaddr *) &struct_socket,
			sizeof(struct sockaddr))) {
		cout << "Error al conectar con el servidor" << endl;
		return 1;
	}
	return 0;
}
//Escribo el string recibido en el Socket.
int Socket::write(void* mensaje, size_t buffer) {
	return this->write(mensaje, buffer, this->conex_id);

}

//Escribe el string recibido en el Socket recibido.
int Socket::write(void* mensaje, size_t buffer, int socket_conex) {
	int nBytesSend = 0;

	//Envio el dato.
	nBytesSend = send(socket_conex, mensaje, buffer, 0);

	return nBytesSend;
}
//Lee un string desde el socket.
void* Socket::read(size_t buffer) {
	return this->read(buffer, this->conex_id);
}
//Lee un string desde el socket indicado.
void* Socket::read(size_t buffer, int socket_conex) {
	int nBytesReceived = 0;

	//Reservo memoria para el mensaje a recibir.
	void* mensaje = malloc(buffer);

	//Recibo el mensaje.
	nBytesReceived = recv(socket_conex, mensaje, buffer, 0);

	if(nBytesReceived > 0)
		return mensaje;
	else
		return NULL;
}

// Cierra el Socket.
void Socket::closeSocket() {
	if (shutdown(socketId, 2))
		cout << "No se puede cerrar el socket" << endl;
}
// Cierra el Socket indicado.
void Socket::closeSocket(int socket_Id) {
	if (shutdown(socket_Id, 2))
		cout << "No se puede cerrar el socket" << endl;
}
//Se envia la IP del cliente
string Socket::getIPCliente() {
	return inet_ntoa(destino.sin_addr);
}
//Se envía la IP del Server.
string Socket::getIPServer() {
	return inet_ntoa(struct_socket.sin_addr);
}
// Permite asignar la ip al socket tanto si recibo IP como nombre.
int Socket::setStruct_Socket(string ip) {
	if (inet_aton(ip.c_str(), &this->struct_socket.sin_addr) != 0) {
		struct hostent *hostinfo;
		hostinfo = gethostbyname(ip.c_str());
		if (hostinfo == NULL) {
			cout << "La dirrección ingresada no es correcta." << endl;
			return 1;
		} else {
			struct_socket.sin_addr = *(struct in_addr *) hostinfo->h_addr;
			return 0;
		}
	}
	return 0;

}
// Geter del socketID.
int Socket::getSocketId() {
	return this->socketId;
}
